﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System.Reflection;
using System.Diagnostics;
namespace GetMySubtitle
{
    using Microsoft.Win32;
    using SubtitleClient;
    using System.Collections.Specialized;
    using FreeTranslator;
    using CommonUtils;

    public partial class GetMySubtitleForm : Form
    {
        #region MEF
        ITextImportController PlugInImportController
        {
            get
            {
                return MEFController.PlugInImportController;
            }
        }
        #endregion
        /*
        // this way of invoking a function
        // is slower when making multiple calls
        // because the assembly is being instantiated each time.
        // But this code is clearer as to what is going on
        internal static Object InvokeMethodSlow(string AssemblyName,
        string ClassName, string MethodName, Object[] args)
        {
            // load the assemly
            Assembly assembly = Assembly.LoadFrom(AssemblyName);
            // Walk through each type in the assembly looking for our class
            foreach (Type type in assembly.GetTypes())
            {
                if (type.IsClass == true)
                {
                    if (type.FullName.EndsWith("." + ClassName))
                    {
                        // create an instance of the object
                        object ClassObj = Activator.CreateInstance(type);
                        // Dynamically Invoke the method
                        object Result = type.InvokeMember(MethodName,
                        BindingFlags.Default | BindingFlags.InvokeMethod,
                        null,
                        ClassObj,
                        args);
                        return (Result);
                    }
                }
            }
            throw (new System.Exception("could not invoke method"));
        }
       */

        /* old code
        public GetMySubtitleForm(string originalPath = null)
        {
            _originalPath = originalPath;
            InitializeComponent();
            StringBuilder sb = new StringBuilder(50);

            PlugInImportController.TextProviders.ToList().ForEach(fr =>
            {
                if (fr.Metadata.IsMovie)
                {
                    if (fr.Metadata.Provider == "")
                        sb.AppendFormat("{0}({1})|{1}|", fr.Metadata.Description, fr.Metadata.FileExtension);
                    else
                        sb.AppendFormat("{0}-{2}({1})|{1}|", fr.Metadata.Description, fr.Metadata.FileExtension, fr.Metadata.Provider);
                }
            });
            sb.Append("All files|*.*");
            this._openFileDialog.Filter = sb.ToString();
            sb.Length = 0;

        }
        
        */

        string _originalPath;
        
        public GetMySubtitleForm(string originalPath = null)
        {
            try
            {
                _originalPath = originalPath;
                InitializeComponent();
                StringBuilder sb = new StringBuilder(50);
                sb.Append("All files|*.*|");
                PlugInImportController.TextProviders.ToList().ForEach(fr =>
                {
                    if (fr.Metadata.IsMovie)
                    {
                        if (fr.Metadata.Provider == "")
                            sb.AppendFormat("{0}({1})|{1}", fr.Metadata.Description, fr.Metadata.FileExtension);
                        else
                            sb.AppendFormat("{0}-{2}({1})|{1}", fr.Metadata.Description, fr.Metadata.FileExtension, fr.Metadata.Provider);
                    }
                });

                this._openFileDialog.Filter = sb.ToString();
                sb.Clear();
                _openFileDialog.FileName = "";
            }
            catch (Exception Ex)
            {

                MessageBox.Show("Exception thrown in ", Ex.Message);
            }
        }
         
        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
        }
        protected override void OnClosed(EventArgs e)
        {

            if (_backgroundWorker.IsBusy)
                _backgroundWorker.CancelAsync();

            global::FreeTranslator.Properties.Settings.Default.Exact = _radioButtonExact.Checked;
            global::FreeTranslator.Properties.Settings.Default.Selected = _radioButtonSelectedLanguage.Checked;
            global::FreeTranslator.Properties.Settings.Default.Any = _radioButtonExistingLanguage.Checked;
            StringCollection lst = new StringCollection();
            for (int i = 0; i < _checkedListBox.CheckedItems.Count; i++)
            {
                SubtitleClient.langMap lng = _checkedListBox.CheckedItems[i] as SubtitleClient.langMap;
                if (lng != null)
                    lst.Add(lng.twoLetter);

            }

            global::FreeTranslator.Properties.Settings.Default.Languages = lst;
            global::FreeTranslator.Properties.Settings.Default.Save();
            base.OnClosed(e);
        }
        private void GetMySubtitleForm_Load(object sender, EventArgs e)
        {
            if (!this.Visible)
                return;
            try
            {
                Assembly crt = Assembly.GetExecutingAssembly();
                object[] attr = crt.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), true);
                AssemblyDescriptionAttribute desc = attr[0] as AssemblyDescriptionAttribute;
                attr = crt.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true);
                AssemblyFileVersionAttribute ver = attr[0] as AssemblyFileVersionAttribute;
                Version v = crt.GetName().Version;
                Text = string.Format("{0} {1}.{2}", Text, v.Major, v.Minor);
                var doc = WebUtils.GoogleTranslator.LoadPersistedData();
                doc = null;

                _checkedListBox.SuspendLayout();
                foreach (langMap aControl in Client.theLangMap.OrderBy(x => x.description))
                {
                    _checkedListBox.Items.Add(aControl, false);
                }
                _checkedListBox.DisplayMember = "description";
                _checkedListBox.ResumeLayout();
                _radioButtonSelectedLanguage.Checked = true;
                _buttonTranslate.Enabled = false;

                _buttonGetSubTitle.Enabled = _checkedListBox.CheckedItems.Count > 0;
                if (global::FreeTranslator.Properties.Settings.Default.Exact)
                {
                    _radioButtonExact.Checked = true;
                    SetCheckedLanguages();
                }
                else if (global::FreeTranslator.Properties.Settings.Default.Selected)
                {
                    _radioButtonSelectedLanguage.Checked = true;
                    SetCheckedLanguages();
                }
                else if (global::FreeTranslator.Properties.Settings.Default.Any)
                    _radioButtonExistingLanguage.Checked = true;
                //if (!Directory.Exists(_txtLocation.Text))
                //    _checkBoxSubfolders.Checked = false;
                _checkBoxSubfolders.Checked = Directory.Exists(_txtLocation.Text);
                if (!_buttonGetSubTitle.Enabled)
                    _toolStripStatusLabel.Text = "Please check at least a language to download";
                if (_originalPath != null && _buttonGetSubTitle.Enabled)
                    this.Invoke(new Action(() => _buttonGetSubTitle_Click(null, null)));
            }
            catch (Exception ex)
            {
                Close();
                return;
            }
            finally
            {

            }

        }

        private void SetCheckedLanguages()
        {
            bool bLangSet = false;
            //if (global::FreeTranslator.Properties.Settings.Default.Languages.Count > 0)
            //{
            foreach (string lang in global::FreeTranslator.Properties.Settings.Default.Languages)
            {
                bLangSet = SetSpecificLanguage(lang);
            }
            //}
            //else
            //{
            if (!bLangSet)
            {
                try
                {
                    FreeTranslatorForm.PersistedData data;
                    FreeTranslatorForm.LoadData(out data);
                    if (!SetSpecificLanguage(data.to))
                        SetSpecificLanguage("en");
                }
                catch (Exception)
                {
                    SetSpecificLanguage("en");
                }
            }

            // }
        }

        private bool SetSpecificLanguage(string lang)
        {
            if(string.IsNullOrEmpty(lang))
                return false;
            bool bFound = false;
            for (int i = 0; i < _checkedListBox.Items.Count; i++)
            {
                SubtitleClient.langMap lng = _checkedListBox.Items[i] as SubtitleClient.langMap;
                if (lng != null && lng.twoLetter == lang)
                {
                    _checkedListBox.SetItemChecked(i, true);
                    bFound = true;
                    if (_radioButtonExact.Checked)
                        break;
                }

            }
            return bFound;
        }
        private void GetMySubtitleForm_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None;
        }
        private delegate void DroppedFileHandler(string s);
        private void GetMySubtitleForm_DragDrop(object sender, DragEventArgs e)
        {
            Array arr = (Array)e.Data.GetData(DataFormats.FileDrop);
            if (arr != null)
            {
                //this.Invoke(new DroppedFileHandler(ProcessFileSystemEntry),
                // new object[1] { arr.GetValue(0).ToString() });
                this.Invoke(new Func<string, bool>(ProcessFileSystemEntry),
                new object[1] { arr.GetValue(0).ToString() });
            }
        }
        private bool ProcessFileSystemEntry(string Entry)
        {
            try
            {
                if (Directory.Exists(Entry))
                {
                    try
                    {
                        Cursor = Cursors.WaitCursor;
                        this._txtLocation.Text = Entry;
                    }
                    catch (Exception ex)
                    {
                        return false;
                    }
                    finally
                    {
                        Cursor = Cursors.Default;
                    }
                }
                else if (File.Exists(Entry))
                {
                    this._txtLocation.Text = Entry;
                }
            }
            finally
            {
            }
            return true;
        }

        int _crtIndex = -1;
        private void _checkedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (this._radioButtonExact.Checked && _crtIndex < 0)
            {
                _crtIndex = e.Index;
                for (int i = 0; i < _checkedListBox.Items.Count; i++)
                    _checkedListBox.SetItemChecked(i, e.Index == i);
                _crtIndex = -1;
            }
            if (e.NewValue == CheckState.Checked)
                _buttonGetSubTitle.Enabled = true;
            else
            {
                _buttonGetSubTitle.Enabled = _checkedListBox.CheckedItems.Count > 1;
            }
            switch (_checkedListBox.CheckedItems.Count)
            {
                case 1:
                case 2:// if (e.NewValue == CheckState.Checked)
                    //   _checkBoxRename.Checked = true;
                    break;

                default:
                    break;
            }

        }

        private void _radioButtonExact_CheckedChanged(object sender, EventArgs e)
        {
            if (_radioButtonExact.Checked == true)
            {
                _checkBoxRename.Enabled = true;
                _crtIndex = -1;
                for (int i = 0; i < _checkedListBox.Items.Count; i++)
                    _checkedListBox.SetItemChecked(i, false);

            }
            else
                _checkBoxRename.Enabled = false;
        }
        private void _radioButtonExistingLanguage_CheckedChanged(object sender, EventArgs e)
        {
            if (_radioButtonExistingLanguage.Checked == true)
            {
                _crtIndex = -1;
                for (int i = 0; i < _checkedListBox.Items.Count; i++)
                    _checkedListBox.SetItemChecked(i, true);
            }
        }
        public void _buttonGetSubTitle_Click(object sender, EventArgs e)
        {
            if (_backgroundWorker.CancellationPending)
                return;
            if (_backgroundWorker.IsBusy)
            {
                _backgroundWorker.CancelAsync();
                _buttonGetSubTitle.Enabled = false;
                _toolStripStatusLabel.Text = "Cancelling";
                return;
            }
            if (_checkedListBox.CheckedItems.Count == 0)
            {
                MessageBox.Show(this, "Select one ore more languages and try again!", "No languages were selected");
                return;
            }
            if (!File.Exists(_txtLocation.Text) && !Directory.Exists(_txtLocation.Text))
            {
                MessageBox.Show(this, '\'' + _txtLocation.Text + "' is not a valid path!", "No target selected");
                return;
            }
            _toolStripStatusLabel.Text = "Starting download";
            _tableLayoutPanel.Controls.OfType<Control>().ToList().ForEach(c => c.Enabled = (c == _buttonGetSubTitle || c == _buttonExit));
            _buttonGetSubTitle.Text = "&Cancel";

            List<string> lst = new List<string>(6);
            lst.Add(_txtLocation.Text);

            IEnumerable<string> a2 = _checkedListBox.CheckedItems.OfType<SubtitleClient.langMap>().Select(x => x.twoLetter);
            string arg2 = string.Join(",", a2.ToArray());
            lst.Add(arg2);
            if (_checkBoxNewOnly.Checked)
                lst.Add("/newonly");
            if (_checkBoxRename.Checked)
                lst.Add("/rename");
            if (_checkBoxFolders.Checked)
                lst.Add("/folders");
            if (_checkBoxSubfolders.Checked)
                lst.Add("/subfolders");
            string[] args = lst.ToArray();
            if (Client.movieFormats == null)
            {
                Client.movieFormats = FreeTranslatorForm.AllMoviesExtensions.Select(s => s.Replace(".", "")).ToArray();
            }

            _backgroundWorker.RunWorkerAsync(args);
            _movieFile = "";
        }
        private void _buttonExit_Click(object sender, EventArgs e)
        {

            Close();
        }
        private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            _movieFile = null;
            BackgroundWorker worker = sender as BackgroundWorker;
            if (0 != Client.Main_old(e.Argument as string[], _backgroundWorker, e))
                e.Result = null;
        }
        private void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {

            if (!_backgroundWorker.CancellationPending)
            {
                if (e.ProgressPercentage == 0)
                    _toolStripStatusLabel.Text = "Info:" + e.UserState as string;
                if (e.ProgressPercentage == 1)
                    _toolStripStatusLabel.Text = "Warning:" + e.UserState as string;
                if (e.ProgressPercentage == 1)
                    _toolStripStatusLabel.Text = "Error:" + e.UserState as string;
            }
        }
        internal string _movieFile;
        private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // First, handle the case where an exception was thrown.
            Application.UseWaitCursor = false;
            if (e.Error != null)
            {
                MessageBox.Show(this, e.Error.Message, "Error getting the subtitles", MessageBoxButtons.OK, MessageBoxIcon.Error);
                _toolStripStatusLabel.Text = e.Error.Message;
                //_buttonTranslate.Enabled = false;
            }
            else if (e.Cancelled)
            {
                // Next, handle the case where the user canceled 
                // the operation.
                // Note that due to a race condition in 
                // the DoWork event handler, the Cancelled
                // flag may not have been set, even though
                // CancelAsync was called.
                _toolStripStatusLabel.Text = "Cancelled";
            }
            else
            {
                // Finally, handle the case where the operation 
                // succeeded.
                if (e.Result != null)
                {
                    _toolStripStatusLabel.Text = string.Format("Downloaded {0} files, last:{1}", e.Result.ToString(), MovieFile._lastSubtitleFileName);
                    try
                    {
                        int cnt = (int)e.Result;
                        _buttonTranslate.Enabled = cnt > 0;
                        _btnPlay.Enabled = (cnt > 0) && File.Exists(_txtLocation.Text);
                        _movieFile = MovieFile._lastSubtitleFileName;

                    }
                    catch
                    {
                        _btnPlay.Enabled = _buttonTranslate.Enabled = false;
                    }
                }
                else
                {
                    _toolStripStatusLabel.Text = string.Format("Some error has occurred");
                    _btnPlay.Enabled = _buttonTranslate.Enabled = false;
                }
            }

            _tableLayoutPanel.Controls.OfType<Control>().ToList().ForEach(c => c.Enabled = true);
            _buttonGetSubTitle.Text = "&Get Subtitle(s)";

            _buttonGetSubTitle.Enabled = true;
        }
        private void _btnSelectDirectory_Click(object sender, EventArgs e)
        {
            if (this._folderBrowserDialog.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
                _txtLocation.Text = _folderBrowserDialog.SelectedPath;
        }
        private void _btnSelectFile_Click(object sender, EventArgs e)
        {
            if (_openFileDialog.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
                _txtLocation.Text = _openFileDialog.FileName;
        }
        private void _buttonTranslate_Click(object sender, EventArgs e)
        {
            string mediaFile = Path.Combine(Path.GetDirectoryName(_txtLocation.Text), Path.GetFileNameWithoutExtension(_txtLocation.Text));
            string[] extensions = new string[] { ".srt", ".sub" };
            string extension = extensions.FirstOrDefault(ext => File.Exists(mediaFile + ext));
            string file = (extension == null) ? MovieFile._lastSubtitleFileName : mediaFile + extension;
            FreeTranslator.FreeTranslatorForm ftf = Application.OpenForms.OfType<FreeTranslator.FreeTranslatorForm>().SingleOrDefault();
            if (ftf == null)
            {


                if (!string.IsNullOrWhiteSpace(file) && File.Exists(file))
                    ftf = new FreeTranslator.FreeTranslatorForm(file);
                else
                    ftf = new FreeTranslator.FreeTranslatorForm();
                ftf.Show();
                Application.DoEvents();
            }
            else
            {

                if (!ftf.Visible)
                {
                    ftf.Show(this);
                }

            }
            Application.DoEvents();
            if (File.Exists(file))
                ftf.ImportTextFromFile(file);//_movieFile
            this.WindowState = FormWindowState.Minimized;

        }
        private void _buttonPlay_Click(object sender, EventArgs e)
        {
            if (File.Exists(_txtLocation.Text))
                StartMediaFile(_txtLocation.Text);
            else
                MessageBox.Show(this, '\'' + _txtLocation.Text + "\' is not a file.\r\nPlease select another one.", "File Missing");
        }
        private bool StartMediaFile(string file)
        {
            const string fileDlgFilter = "Srt Files|*.srt|Sub Files|*.sub|All files|*.*";
            //const string fileDlgFilter = "Media Files|*.avi;*.mkv|Avi Files|*.avi|Matroska Files|*.mkv|All files|*.*";
            bool res = false;
            string mediaFile = Path.Combine(Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file));
            string[] extensions = new string[] { ".srt", ".sub" };
            string extension = extensions.FirstOrDefault(ext => File.Exists(mediaFile + ext));
            if (!string.IsNullOrEmpty(extension))
            {
                this.UseWaitCursor = true;
                _btnPlay.Enabled = false;
                Application.DoEvents();
                try
                {
                    //Process.Start(string.Format("\"{0}\"", file));//.WaitForInputIdle(3000);
                    StartVideo(file);
                }
                catch
                { }
                finally
                {
                    this.UseWaitCursor = false;
                    _btnPlay.Enabled = true;
                }
            }
            else
                if (MessageBox.Show(this, string.Format("The '{0}.???'\r\nsubtitle could not be found.\r\nWould you like to select it?", mediaFile)
                    , "Can't find the subtitle file", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    try
                    {
                        OpenFileDialog ofd = new OpenFileDialog();
                        ofd.InitialDirectory = Path.GetDirectoryName(file);
                        ofd.Multiselect = false;
                        ofd.SupportMultiDottedExtensions = true;
                        ofd.Filter = fileDlgFilter;
                        ofd.FilterIndex = 1;
                        if (ofd.ShowDialog(this) == DialogResult.OK)
                        {
                            extension = Path.GetExtension(ofd.FileName);
                            File.Copy(ofd.FileName, mediaFile + extension);
                            this.UseWaitCursor = true;
                            _btnPlay.Enabled = false;
                            Application.DoEvents();

                            StartVideo(file);
                        }
                        else
                            res = true;
                        ofd.Dispose();
                    }
                    catch (Exception ex)
                    {
                        _statusStrip.Text = ex.Message;
                    }
                    finally
                    {
                        this.UseWaitCursor = false;
                        _btnPlay.Enabled = true;
                    }
                }
                else
                    res = true;
            return res;
        }

        public static void StartVideo(string file)
        {
            //string crtDir = Environment.CurrentDirectory;
            //System.Environment.CurrentDirectory = Path.GetDirectoryName(file);
            //var p = Process.Start(string.Format("\"{0}\"", file));
            //System.Threading.Thread.Sleep(1000);
            //Environment.CurrentDirectory = crtDir;
            ProcessStartInfo pInfo = new ProcessStartInfo(string.Format("\"{0}\"", file));
            pInfo.WorkingDirectory = Path.GetDirectoryName(file);
            pInfo.UseShellExecute = true;//default
            Process p = Process.Start(pInfo);


        }

        private void _txtLocation_TextChanged(object sender, EventArgs e)
        {
            _checkBoxSubfolders.Enabled = _txtLocation.Text.Length > 0 && Directory.Exists(_txtLocation.Text);
        }
    }
}
